﻿#include "Utils.h"
#include <QMessageBox>
#include <Windows.h>

namespace Utils {

static bool IsDelim(char c, const char *pDelims)
{
    while (*pDelims) {
        if (c == *pDelims++)
            return true;
    }

    return false;
}

char *STRTOK_R(char *pStr, const char *pDelims, char **ppSave)
{
    if (!pStr)
        pStr = *ppSave;

    while (IsDelim(*pStr, pDelims))
        pStr++;

    if (!*pStr) {
        *ppSave = pStr;
        return nullptr;
    }

    char *pToken = pStr;

    while (*pStr && !IsDelim(*pStr, pDelims))
        pStr++;

    if (*pStr)
        *pStr++ = 0;

    *ppSave = pStr;

    return pToken;
}

bool StrToInt(const char *pStr, int *pNum)
{
    bool res = false;
    int num;
    int sign = 1;

    switch (*pStr) {
    case '-':
        sign = -1;
    case '+':
        pStr++;
        break;
    }

    for (num = 0 ;; pStr++) {
        switch (*pStr) {
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            num = num*10 + (*pStr - '0');
            res = true;
            continue;
        case 0:
            break;
        default:
            res = false;
        }
        break;
    }

    if (pNum)
        *pNum = num*sign;

    return res;
}

bool askYesNoDialog(const QString &title,
                    const QString &text,
                    QMessageBox::StandardButtons buttons,
                    QMessageBox::StandardButton defaultButton,
                    QWidget *parent)
{
    QMessageBox::StandardButton reply = QMessageBox::question(
        parent,
        title,
        text,
        buttons,
        defaultButton);

    return reply == QMessageBox::Yes;
}

int askOkCancelDialog(const QString &title,
                      const QString &text,
                      QWidget *parent)
{
    QMessageBox::StandardButton reply = QMessageBox::question(
        parent,
        title,
        text,
        QMessageBox::Ok | QMessageBox::Cancel,
        QMessageBox::Ok);

    return (reply == QMessageBox::Ok) ? IDCONTINUE : IDCANCEL;
}

int askCancelTryContinueDialog(const QString &title,
                               const QString &text,
                               QWidget *parent)
{
    // 使用标准按钮近似映射：Yes=Continue, Retry=Try Again, Cancel=Cancel
    QMessageBox::StandardButton reply = QMessageBox::question(
        parent,
        title,
        text,
        QMessageBox::Yes | QMessageBox::Retry | QMessageBox::Cancel,
        QMessageBox::Yes);

    switch (reply) {
    case QMessageBox::Yes:
        return IDCONTINUE;
    case QMessageBox::Retry:
        return IDTRYAGAIN;
    case QMessageBox::Cancel:
    default:
        return IDCANCEL;
    }
}

QString formatWinError(DWORD errorCode)
{
    if (errorCode == ERROR_SUCCESS)
        return QStringLiteral("ERROR_SUCCESS");

    auto formatFromModule = [&](const wchar_t* moduleName) -> QString {
        HMODULE hmod = GetModuleHandleW(moduleName);
        if (!hmod) return QString();

        LPWSTR buf = nullptr;
        DWORD sz = FormatMessageW(
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_HMODULE |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            hmod,
            errorCode,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPWSTR)&buf,
            0,
            nullptr);
        QString msg;
        if (sz && buf) {
            msg = QString::fromWCharArray(buf).trimmed();
            LocalFree(buf);
        }
        return msg;
    };

    // First try system table
    LPWSTR buffer = nullptr;
    DWORD size = FormatMessageW(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        nullptr,
        errorCode,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPWSTR)&buffer,
        0,
        nullptr);

    QString message;
    if (size && buffer) {
        message = QString::fromWCharArray(buffer).trimmed();
        LocalFree(buffer);
    }

    // If system table didn't have a message, try common driver/setup modules
    if (message.isEmpty()) {
        static const wchar_t* modules[] = { L"setupapi.dll", L"newdev.dll", L"cfgmgr32.dll" };
        for (auto m : modules) {
            message = formatFromModule(m);
            if (!message.isEmpty()) break;
        }
    }

    if (message.isEmpty()) {
        message = QStringLiteral("Unknown error");
    }

    return QString("Error %1 (0x%2): %3")
            .arg((unsigned long)errorCode)
            .arg((unsigned long)errorCode, 0, 16)
            .arg(message);
}

QString formatCfgMgrError(CONFIGRET cr)
{
    // 常见 CONFIGRET 错误码的名称映射
    switch (cr) {
    case CR_SUCCESS:                return QStringLiteral("CR_SUCCESS (0)");
    case CR_DEFAULT:                return QStringLiteral("CR_DEFAULT (1)");
    case CR_OUT_OF_MEMORY:          return QStringLiteral("CR_OUT_OF_MEMORY (3)");
    case CR_INVALID_POINTER:        return QStringLiteral("CR_INVALID_POINTER (7)");
    case CR_INVALID_DEVNODE:        return QStringLiteral("CR_INVALID_DEVNODE (13)");
    case CR_INVALID_DEVICE_ID:      return QStringLiteral("CR_INVALID_DEVICE_ID (15)");
    case CR_NO_SUCH_DEVNODE:        return QStringLiteral("CR_NO_SUCH_DEVNODE (18)");
    case CR_ACCESS_DENIED:          return QStringLiteral("CR_ACCESS_DENIED (21)");
    case CR_NOT_DISABLEABLE:        return QStringLiteral("CR_NOT_DISABLEABLE (25)");
    case CR_NOT_SYSTEM_VM:          return QStringLiteral("CR_NOT_SYSTEM_VM (35)");
    case CR_INVALID_PROPERTY:       return QStringLiteral("CR_INVALID_PROPERTY (39)");
    case CR_INVALID_DATA:           return QStringLiteral("CR_INVALID_DATA (40)");
    case CR_INVALID_API:            return QStringLiteral("CR_INVALID_API (51)");
    default:
        return QString("CONFIGRET %1").arg((unsigned long)cr);
    }
}

}
